package com.tanhua.dubbo.server.api;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.dubbo.server.enums.CommentType;
import com.tanhua.dubbo.server.enums.IdType;
import com.tanhua.dubbo.server.pojo.*;
import com.tanhua.dubbo.server.service.IdService;
import com.tanhua.dubbo.server.service.TimeLineService;
import com.tanhua.dubbo.server.vo.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;



import java.util.ArrayList;
import java.util.List;

@Service(version = "1.0.0")
@Slf4j
public class QuanZiApiImpl implements QuanZiApi {
  @Autowired
  private MongoTemplate mongoTemplate;
  @Autowired
  private IdService idService;
  @Autowired
   private TimeLineService timeLineService;
  @Autowired
   private RedisTemplate<String,String>redisTemplate;
  @Autowired
   private VideoApi videoApi;
    //评论数据存储在Redis中key的前缀
    private static final String COMMENT_REDIS_KEY_PREFIX = "QUANZI_COMMENT_";

    //用户是否点赞的前缀
    private static final String COMMENT_USER_LIEK_REDIS_KEY_PREFIX = "USER_LIKE_";

    //用户是否喜欢的前缀
    private static final String COMMENT_USER_LOVE_REDIS_KEY_PREFIX = "USER_LOVE_";

    @Override
    public PageInfo<Publish> queryPublishList(Long userId, Integer page, Integer pageSize) {
        PageInfo<Publish> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        Pageable pageable = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("date")));
        Query query=new Query().with(pageable);
        List<com.tanhua.dubbo.server.pojo.TimeLine> timeLineList = mongoTemplate.find(query, TimeLine.class, "quanzi_time_line_"+ userId);
        if(CollUtil.isEmpty(timeLineList)){
            return pageInfo;
        }
        List<Object> publishIds = CollUtil.getFieldValues(timeLineList, "publishId");
        Query query1 = Query.query(Criteria.where("id").in(publishIds))
                .with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishes = mongoTemplate.find(query1, Publish.class);
        pageInfo.setRecords(publishes);
        return pageInfo;
    }

    @Override
    public String savePublish(Publish publish) {
        if(!ObjectUtil.isAllNotEmpty(publish.getText(),publish.getUserId())){
            return null;
        }
        try {
            publish.setPid(idService.createId(IdType.PUBLISH));
            publish.setCreated(System.currentTimeMillis());
            mongoTemplate.save(publish);
            Album album = new Album();
            album.setCreated(System.currentTimeMillis());
            album.setId(ObjectId.get());
            album.setPublishId(publish.getId());
            mongoTemplate.save(album, "quanzi_album_" + publish.getUserId());
            timeLineService.saveTimeLine(publish.getUserId(),publish.getId());
        } catch (Exception e) {
            log.error("发布动态失败",e);
        }
         return publish.getId().toHexString();
    }

    @Override
    public PageInfo<Publish> queryRecommendPublishList(Long userId, Integer page, Integer pageSize) {
        PageInfo<Publish> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        String key = "QUANZI_PUBLISH_RECOMMEND_" + userId;
        String data = redisTemplate.opsForValue().get(key);
        if(StringUtils.isEmpty(data)){
            return pageInfo;
        }
        // 手动进行分页
        List<String> pids = StrUtil.split(data, ',');
        // 从第几条开始查询  = (当前页码-1)*每页显示的条数
        // 查询到第几条(对比最大的角标)  =  开始的角标 + 每页显示的条数
        // 10条  9  4条  11

        // 客户端给我传递过来的是 页码  而我需要的是 第几条
        // 第几条开始查询 =  (页码-1)*每页显示的条数(每次查询的条数)
        //int startIndex = (page-1)*pageSize;
        //int endIndex = startIndex + pageSize;
        // 30条  29  35  12 6


        // 我们需要自己做逻辑分页  物理分页
        // 计算分页  你传递一个页码和要查询的条数  我给你返回从第几条开始查询  查询到第几条
        // (当前页码-1)*每页要显示的数据 = 从第几条开始查询  + 要查询的条数
        //[0, 10]
        // 2  10   0--9  (2-1)*10  10 + 10 = 20-1
        //  [3233,3292...]
        int[] startEnd = PageUtil.transToStartEnd(page - 1, pageSize);
        int startIndex = startEnd[0]; //从第几条开始查询
        int endIndex = Math.min(startEnd[1], pids.size()); //查询到第几条结束

        // 这个集合是我们分页完成后的要查询的pid的集合
        List<Long> pidLongList = new ArrayList<>();
        for (int i = startIndex; i < endIndex; i++) {
            pidLongList.add(Long.valueOf(pids.get(i)));
        }
        if(CollUtil.isEmpty(pidLongList)){
            return pageInfo;
        }
        Query query = Query.query(Criteria.where("pid").in(pidLongList))
                .with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishes = mongoTemplate.find(query, Publish.class);
        if(CollUtil.isEmpty(pidLongList)){
            return pageInfo;
        }
         pageInfo.setRecords(publishes);
         return pageInfo;
    }

    @Override
    public Publish queryPublishById(String id) {
        return mongoTemplate.findById(id,Publish.class);
    }
    private String getCommentRedisKeyPrefix(String publishId){
        return COMMENT_REDIS_KEY_PREFIX+publishId;
    }
    private String getCommentUserLiekRedisKeyPrefix(Long userId){
        return COMMENT_USER_LIEK_REDIS_KEY_PREFIX+userId;
    }

    @Override
    public Boolean likeComment(Long userId, String publishId) {
        Boolean result = queryUserIsLike(userId, publishId);
        if (result){
            return false;
        }
      boolean saveresult=saveComment(userId,publishId, CommentType.LIKE,null);
        if(!saveresult){
            return false;
        }
        String redisKey = getCommentRedisKeyPrefix(publishId);
        String haskey= CommentType.LIKE.toString();
        redisTemplate.opsForHash().increment(redisKey,haskey,1);
        String userhaskey = getCommentUserLiekRedisKeyPrefix(userId);
        redisTemplate.opsForHash().increment(redisKey,userhaskey,1);
        return true;
    }

    private boolean saveComment(Long userId, String publishId, CommentType like, String content) {
        try {
            Comment comment = new Comment();
            comment.setId(ObjectId.get());
            comment.setUserId(userId);
            comment.setCommentType(like.getType());
            comment.setPublishId(new ObjectId(publishId));
            comment.setContent(content);
            comment.setCreated(System.currentTimeMillis());
            Publish publish = queryPublishById(publishId);
            if(ObjectUtil.isNotEmpty(publish)){
                comment.setPublishUserId(publish.getUserId());
            }else{
              Comment mycomment= queryCommentById(publishId);
              if(ObjectUtil.isNotEmpty(mycomment)){
                  comment.setPublishUserId(mycomment.getUserId());
              }else{
                  Comment myComment = queryCommentById(publishId);
                  if (ObjectUtil.isNotEmpty(myComment)){
                      comment.setPublishUserId(myComment.getUserId());
                  }else{
                  Video video= videoApi.queryVideoById(publishId);
                  if (ObjectUtil.isNotEmpty(video)) {
                      comment.setPublishUserId(video.getUserId());
                  }else{
                      return false;
                  }
                  }
              }
            } mongoTemplate.save(comment);
              return true;
        } catch (Exception e) {
            log.error("保存Comment出错~ userId = " + userId + ", publishId = " + publishId + ", commentType = " + like, e);
        }return false;

    }

    private Comment queryCommentById(String publishId) {
        return mongoTemplate.findById(new ObjectId(publishId),Comment.class);
    }

    @Override
    public Boolean disLikeComment(Long userId, String publishId) {
        Boolean result = queryUserIsLike(userId, publishId);
        if(!result){
            return false;
        }
       Boolean removeresult = removeComment(userId,publishId,CommentType.LIKE);
        if(!removeresult){
            return false;
        }
        String redisKey = getCommentRedisKeyPrefix(publishId);
        String haskey= CommentType.LIKE.toString();
        redisTemplate.opsForHash().increment(redisKey,haskey,-1);
        String userhaskey = getCommentUserLiekRedisKeyPrefix(userId);
        redisTemplate.opsForHash().delete(redisKey,userhaskey);
        return true;
    }

    private Boolean removeComment(Long userId, String publishId, CommentType like) {
        Query query = Query.query(Criteria.where("userId").is(userId)
                .and("publishId").is(new ObjectId(publishId))
                .and("commentType").is(like.getType()));
        return mongoTemplate.remove(query,Comment.class).getDeletedCount()>0;
    }

    @Override
    public Long queryLikeCount(String publishId) {
        String redisKey = getCommentRedisKeyPrefix(publishId);
        String haskey= CommentType.LIKE.toString();
        Object data = redisTemplate.opsForHash().get(redisKey, haskey);
        if (ObjectUtil.isNotEmpty(data)){
            return Convert.toLong(data);
        }
        Long count= queryCommentCount(publishId,CommentType.LIKE);
        redisTemplate.opsForHash().put(redisKey,haskey,String.valueOf(count));
        return count;
    }

    private Long queryCommentCount(String publishId, CommentType like) {
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(publishId))
                .and("commentType").is(like.getType()));
        return mongoTemplate.count(query,Comment.class);
    }

    @Override
    public Boolean queryUserIsLike(Long userId, String publishId) {
        String redisKey = getCommentRedisKeyPrefix(publishId);
        String userhaskey = getCommentUserLiekRedisKeyPrefix(userId);
        Object data = redisTemplate.opsForHash().get(redisKey, userhaskey);
        if(ObjectUtil.isNotEmpty(data)){
            return StrUtil.equals(Convert.toStr(data),"1");
        }
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(publishId))
                .and("userId").is(userId)
                .and("commentType").is(CommentType.LIKE.getType()));
        long count = mongoTemplate.count(query, Comment.class);
        if(count==0){
            return false;
        }
        redisTemplate.opsForHash().put(redisKey,userhaskey,"1");
        return true;
    }

    @Override
    public Boolean loveComment(Long userId, String publishId) {
        Boolean result = queryUserIsLove(userId, publishId);
        if(result){
            return false;
        }
        boolean saveresult = saveComment(userId, publishId, CommentType.LOVE, null);
        if (!saveresult){
            return false;
        }
        String redisKey = getCommentRedisKeyPrefix(publishId);
        String haskey= CommentType.LOVE.toString();
        redisTemplate.opsForHash().increment(redisKey,haskey,1);
        haskey =getCommentUserLoveRedisKey(userId);
        redisTemplate.opsForHash().put(redisKey,haskey,"1");
        return true;
    }

    private String getCommentUserLoveRedisKey(Long userId) {
        return COMMENT_USER_LOVE_REDIS_KEY_PREFIX + userId;
    }

    @Override
    public Boolean disLoveComment(Long userId, String publishId) {
        Boolean result = queryUserIsLove(userId, publishId);
        if(!result){
            return false;
        }
        Boolean removeresult = removeComment(userId, publishId, CommentType.LOVE);
        if(!removeresult){
            return false;
        }
        String redisKey = getCommentRedisKeyPrefix(publishId);
        String haskey =getCommentUserLoveRedisKey(userId);
        redisTemplate.opsForHash().delete(redisKey,haskey);
        redisTemplate.opsForHash().increment(redisKey,CommentType.LOVE.toString(),-1);
        return true;
    }

    @Override
    public Long queryLoveCount(String publishId) {
        String redisKey = getCommentRedisKeyPrefix(publishId);
        String haskey= CommentType.LOVE.toString();
        Object data = redisTemplate.opsForHash().get(redisKey, haskey);
        if (ObjectUtil.isNotEmpty(data)){
            return Convert.toLong(data);
        }
        Long count = queryCommentCount(publishId, CommentType.LOVE);
        redisTemplate.opsForHash().put(redisKey,haskey,String.valueOf(count));
        return count;
    }

    @Override
    public Boolean queryUserIsLove(Long userId, String publishId) {
        String redisKey = getCommentRedisKeyPrefix(publishId);
        String userhaskey = getCommentUserLiekRedisKeyPrefix(userId);
        Object data = redisTemplate.opsForHash().get(redisKey, userhaskey);
        if(ObjectUtil.isNotEmpty(data)){
            return StrUtil.equals(Convert.toStr(data),"1");
        }
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(publishId))
                .and("userId").is(userId)
                .and("commentType").is(CommentType.LOVE.getType()));
        long count = mongoTemplate.count(query, Comment.class);
        if(count==0){
            return false;
        }
        redisTemplate.opsForHash().put(redisKey,userhaskey,"1");
        return true;
    }

    @Override
    public PageInfo<Comment> queryCommentList(String publishId, Integer page, Integer pageSize) {
        PageRequest pageRequest =PageRequest.of(page-1,pageSize,Sort.by(Sort.Order.asc("created")));
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(publishId))
                .and("commentType").is(CommentType.COMMENT.getType())).with(pageRequest);
        List<Comment> commentList = mongoTemplate.find(query, Comment.class);
        PageInfo<Comment> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(commentList);
        return pageInfo;
    }

    @Override
    public Boolean saveComment(Long userId, String publishId, String content) {
        return saveComment(userId,publishId,CommentType.COMMENT,content);
    }

    @Override
    public Long queryCommentCount(String publishId) {
        return queryCommentCount(publishId,CommentType.COMMENT);
    }
    @Override
    public PageInfo<Comment> queryLikeCommentListByUser(Long userId, Integer page, Integer pageSize) {
        return this.queryCommentListByUser(userId, CommentType.LIKE, page, pageSize);
    }


    // 谁对你喜欢了
    @Override
    public PageInfo<Comment> queryLoveCommentListByUser(Long userId, Integer page, Integer pageSize) {
        return this.queryCommentListByUser(userId, CommentType.LOVE, page, pageSize);
    }

    // 谁对你评论了
    @Override
    public PageInfo<Comment> queryCommentListByUser(Long userId, Integer page, Integer pageSize) {
        return this.queryCommentListByUser(userId, CommentType.COMMENT, page, pageSize);
    }

    /**
     * 根据登录用户的ID 查询 哪些人对你点赞了/喜欢了/评论了
     * @param userId
     * @param commentType
     * @param page
     * @param pageSize
     * @return
     */
    private PageInfo<Comment> queryCommentListByUser(Long userId, CommentType commentType, Integer page, Integer pageSize) {

        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));

        Query query = Query.query(Criteria.where("publishUserId").is(userId)
                .and("commentType").is(commentType.getType())).with(pageRequest);
        List<Comment> commentList = this.mongoTemplate.find(query, Comment.class);

        PageInfo<Comment> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(commentList);

        return pageInfo;
    }

    /**
     * 查询个人相册
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    // userId 要查询的那个人的ID
    @Override
    public PageInfo<Publish> queryAlbumList(Long userId, Integer page, Integer pageSize) {

        PageInfo<Publish> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);

        PageRequest pageRequest = PageRequest.of(page - 1 , pageSize,
                Sort.by(Sort.Order.desc("created")));
        Query query = new Query().with(pageRequest);

        // 查询用户的相册表
        // userId 查询的人的id
        List<Album> albumList = this.mongoTemplate.find(query, Album.class, "quanzi_album_" + userId);

        if(CollUtil.isEmpty(albumList)){
            return pageInfo;
        }

        List<Object> publishIdList = CollUtil.getFieldValues(albumList, "publishId");

        Query queryPublish = Query.query(Criteria.where("id").in(publishIdList))
                .with(Sort.by(Sort.Order.desc("created")));

        // 再根据圈子id去查询圈子表
        List<Publish> publishList = this.mongoTemplate.find(queryPublish, Publish.class);

        pageInfo.setRecords(publishList);

        return pageInfo;
    }
}



